/*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
*
*
* Authors:                  zhoujian
* Email:            343600434@qq.com
* Date:         Aug-30-2024 11:00:48
*
*/


#include "jsm1302z.h"


#include <time.h>
#include "gd32l23x.h"
#include "gd32l23x_eval.h"
#include <string.h>
#include "device.h"
#include "uart_parse.h"

#include <stdio.h>

//#define DEBUG_PRINTF

CALENDAR calendar;

JSM1302Z_zTypeDef jsm1302z_state;
uint8_t two_min_start_min;
uint8_t two_min_start_sec;
uint8_t two_min_min;
uint8_t two_min_sec;
uint32_t jsm1302z_lock_time;

volatile uint8_t time_end;
volatile uint8_t show_time_update;
volatile uint8_t no_rtc;
void nop()
{
    volatile uint8_t t;

    for(t = 0; t < 2; t++) {
        ;
    }
}

uint8_t read_jsm1302z(uint8_t cmd)
{
    uint8_t i, tmp;
    //return 0;
    I2C_SCL_L;
    nop();
    RST_OFF;
    nop();
    I2C_SDA_OUTPUT;
    I2C_SCL_L;
    nop();
    RST_ON;
    nop();

    //cmd = 0x11;
    for(i = 0; i < 8; i++) {
        if(cmd & (1 << i)) {
            I2C_SDA_H;
            nop();

        } else {
            I2C_SDA_L;
            nop();
        }

        I2C_SCL_L;
        nop();
        I2C_SCL_H;
        nop();
    }

    I2C_SDA_INPUT;
    tmp = 0;

    for(i = 0; i < 8; i++) {
        I2C_SCL_H;
        nop();
        I2C_SCL_L;
        nop();

        if(IS_I2C_SDA_H) {
            tmp |= (1 << i);

        } else {
            tmp &= ~(1 << i);
        }
    }

    RST_OFF;
    nop();
    return tmp;
}

uint8_t write_jsm1302z(uint8_t cmd, uint8_t dat)
{
    uint8_t i, tmp;
    I2C_SCL_L;
    nop();
    RST_OFF;
    nop();
    I2C_SDA_OUTPUT;
    I2C_SCL_L;
    nop();
    RST_ON;
    nop();

    //cmd = 0x11;
    for(i = 0; i < 8; i++) {
        if(cmd & (1 << i)) {
            I2C_SDA_H;
            nop();

        } else {
            I2C_SDA_L;
            nop();
        }

        I2C_SCL_L;
        nop();
        I2C_SCL_H;
        nop();
    }

    //I2C_SDA_INPUT;

    //tmp = 0;
    for(i = 0; i < 8; i++) {
        if(dat & (1 << i)) {
            I2C_SDA_H;
            nop();

        } else {
            I2C_SDA_L;
            nop();
        }

        I2C_SCL_L;
        nop();
        I2C_SCL_H;
        nop();
    }

    RST_OFF;
    nop();
    return tmp;
}


unsigned char BCD2HEX(unsigned char val)
{
    unsigned char i;
    i = val & 0x0f;
    val >>= 4;
    val &= 0x0f;
    val *= 10;
    i += val;
    return i;
}

unsigned short B_BCD(unsigned char val)
{
    unsigned char i, j, k;
    i = val / 10;
    j = val % 10;
    k = j + (i << 4);
    return k;
}


//本地时间生成时间戳函数

uint32_t TimeToTimeStamp(CALENDAR* canlendar)
{
    struct tm stm;
    memset(&stm, 0, sizeof(stm));
    stm.tm_year = canlendar->year + 100; //RTC_Year 2023,but tm_year since 1900
    stm.tm_mon = canlendar->mon - 1; //RTC_Month rang 1-12,but tm_mon rang 0-11
    stm.tm_mday = canlendar->mday;      //RTC_Date rang 1-31 and tm_mday rang 1-31
    stm.tm_hour = canlendar->hour - 8; //RTC_Hours rang 0-23 and tm_hour rang 0-23
    stm.tm_min = canlendar->min;    //RTC_Minutes rang 0-59 and tm_min rang 0-59
    stm.tm_sec = canlendar->sec;
    return mktime(&stm);
}

//时间戳解析成本地时间函数
void TimeStampToTime(uint32_t TimeStamp)
{
    struct tm* stm = NULL;
    CALENDAR calendar;
    stm = localtime(&TimeStamp);
    //calendar.year = stm->tm_year + 1900;
    calendar.year = (stm->tm_year + 1900) % 2000;
    calendar.mon = stm->tm_mon + 1;
    calendar.mday = stm->tm_mday;
    calendar.hour = stm->tm_hour + 8;
    calendar.min = stm->tm_min;
    calendar.sec = stm->tm_sec;
    //log_debug("year:%d mon:%d date:%d\n",calendar.year,calendar.mon,calendar.mday);
    //log_debug("hour:%d min:%d sec:%d\n",calendar.hour,calendar.min,calendar.sec);
    //write_jsm1302z(0xC1, calendar.sec);
    write_jsm1302z(0x8e, 0);
    write_jsm1302z(0x80, B_BCD(calendar.sec));
    write_jsm1302z(0x82, B_BCD(calendar.min));
    write_jsm1302z(0x84, B_BCD(calendar.hour));
    write_jsm1302z(0x86, B_BCD(calendar.mday));
    write_jsm1302z(0x88, B_BCD(calendar.mon));
    write_jsm1302z(0x8c, B_BCD(calendar.year));
    write_jsm1302z(0x8e, 0x80);
}

void TimeStampToTime2(uint32_t TimeStamp)
{
    struct tm* stm = NULL;
    CALENDAR calendar;
    stm = localtime(&TimeStamp);
    //calendar.year = stm->tm_year + 1900;
    calendar.year = (stm->tm_year + 1900) % 2000;
    calendar.mon = stm->tm_mon + 1;
    calendar.mday = stm->tm_mday;
    calendar.hour = stm->tm_hour + 8;
    calendar.min = stm->tm_min;
    calendar.sec = stm->tm_sec;
    //log_debug("year:%d mon:%d date:%d\n",calendar.year,calendar.mon,calendar.mday);
    //log_debug("hour:%d min:%d sec:%d\n",calendar.hour,calendar.min,calendar.sec);
    write_jsm1302z(0x8e, 0);
    write_jsm1302z(0xC0, B_BCD(calendar.sec));
    write_jsm1302z(0xC2, B_BCD(calendar.min));
    write_jsm1302z(0xC4, B_BCD(calendar.hour));
    write_jsm1302z(0xC6, B_BCD(calendar.mday));
    write_jsm1302z(0xC8, B_BCD(calendar.mon));
    write_jsm1302z(0xCc, B_BCD(calendar.year));
    write_jsm1302z(0x8e, 0x80);
}

void jsm1302z_task(void)
{
    switch(jsm1302z_state) {
        case JSM1302Z_State_0x00:
            jsm1302z_state = JSM1302Z_State_0x01;
            break;

        case JSM1302Z_State_0x01:
            jsm1302z_state = JSM1302Z_State_0x02;
            break;

        case JSM1302Z_State_0x02:
            jsm1302z_state = JSM1302Z_State_0x03;
            break;

        case JSM1302Z_State_0x03:
            jsm1302z_state = JSM1302Z_State_0x00;
            break;

        default:
            jsm1302z_state = JSM1302Z_State_0x00;
            break;
    }
}
void jsm1302z_deinit(void)
{
    jsm1302z_state = JSM1302Z_State_0x00;
    rcu_periph_clock_enable(RCU_GPIOB);
    gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP,  GPIO_PIN_12);
    gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,  GPIO_PIN_11);
    gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,  GPIO_PIN_13);
    RST_OFF;
    I2C_SCL_L;
}




uint8_t get_show_time(void)
{
    static uint8_t pre_sec;
    calendar.year = read_jsm1302z(0x8d);
    calendar.year = BCD2HEX(calendar.year);
    calendar.mon = read_jsm1302z(0x89);
    calendar.mon = BCD2HEX(calendar.mon);
    calendar.mday = read_jsm1302z(0x87);
    calendar.mday = BCD2HEX(calendar.mday);
    calendar.hour = read_jsm1302z(0x85);
    calendar.hour &= 0x3f;
    calendar.hour = BCD2HEX(calendar.hour);
    calendar.min = read_jsm1302z(0x83);
    calendar.min = BCD2HEX(calendar.min);
    calendar.sec = read_jsm1302z(0x81);
    calendar.sec = BCD2HEX(calendar.sec);
    //log_debug("year:%d mon:%d date:%d\n",calendar.year,calendar.mon,calendar.mday);
    //log_debug("hour:%d min:%d sec:%d\n",calendar.hour,calendar.min,calendar.sec);

    if(pre_sec != calendar.sec) {
        pre_sec = calendar.sec;
        show_time_update = 1;
        return 1;
    }

    return 0;
}

uint8_t jsm1302z_is_time_end()
{
    uint8_t temp_min, temp_sec;
    static uint8_t sec = 0;

    if(time_end || (jihuo_t[6] == 0)) {
        return 1;
    }

    two_min_min = read_jsm1302z(0x83);
    two_min_min = BCD2HEX(two_min_min);
    two_min_sec = read_jsm1302z(0x81);
    two_min_sec = BCD2HEX(two_min_sec);

    if(two_min_sec == 165) {
        if(two_min_min == 165) {
            no_rtc = 1;

            if(sec++ >= 15) {
                return 1;

            } else {
                return 0;
            }
        }

    } else {
        no_rtc = 0;
    }

#ifdef DEBUG_PRINTF
    log_debug("%d:%d ---> %d:%d\n", two_min_start_min, two_min_start_sec, two_min_min, two_min_sec);
#endif

    //if(two_min_start_min+2<two_min_min)
    if(two_min_min >= two_min_start_min) {
        temp_min = two_min_min - two_min_start_min;

    } else {
        temp_min = 60 -  two_min_start_min + two_min_min ;
    }

    if(two_min_sec >= two_min_start_sec) {
        temp_sec = two_min_sec - two_min_start_sec;

    } else {
        temp_sec = 60 -  two_min_start_sec + two_min_sec ;
        temp_min--;
    }

    if((temp_min >= 0) && (temp_sec >= jsm1302z_lock_time)) {
        return 1;
    }

    return 0;
}



void jsm1302z_get_ram_time_start()
{
    uint8_t t = read_jsm1302z(0xC3);
    t = BCD2HEX(t);
    log_debug("ram: %d ", t);
    t = read_jsm1302z(0xC1);
    t = BCD2HEX(t);
    log_debug(" %d \n", t);
}

void jsm1302z_set_ram_time_start()
{
    //two_min_start_min;
    //two_min_start_sec;
    //jsm1302z_lock_time;
    uint32_t timestamp = TimeToTimeStamp(&calendar);
    log_debug("timestamp %d\n", timestamp);
    timestamp += jsm1302z_lock_time;
    TimeStampToTime2(timestamp);
    //write_jsm1302z(0x8E, 0);
    //write_jsm1302z(0xC0, B_BCD(calendar.sec));
    //write_jsm1302z(0xC2, B_BCD(calendar.min));
    //write_jsm1302z(0x8E, 0x80);
    /*uint8_t t = read_jsm1302z(0xC3);
    t = BCD2HEX(t);
    log_debug("write ram: %x ",t);
    t = read_jsm1302z(0xC1);
    t = BCD2HEX(t);
    log_debug(" %x \n",t);*/
}

void jsm1302z_get_time_start()
{
    two_min_start_min = read_jsm1302z(0x83);
    two_min_start_min = BCD2HEX(two_min_start_min);
    two_min_start_sec = read_jsm1302z(0x81);
    two_min_start_sec = BCD2HEX(two_min_start_sec);

    if(two_min_start_sec == 165) {
        if(two_min_start_min == 165) {
            two_min_start_sec = 0;
            two_min_start_min = 0;
            no_rtc = 1;
        }

    } else {
        no_rtc = 0;
    }

    time_end = 0;
}
void jsm1302z_read_time(void)
{
    get_show_time();
#ifdef DEBUG_PRINTF
    log_debug("year:%d", calendar.year);
    log_debug("-%d", calendar.mon);
    log_debug("-%d", calendar.mday);
    log_debug(" %d", calendar.hour);
    log_debug(":%d", calendar.min);
    log_debug(":%d\n", calendar.sec);
#endif
    //jsm1302z_set_ram_time_start();

    if(jsm1302z_is_time_end()) {
        time_end = 1;
#ifdef DEBUG_PRINTF
        log_debug("2min end \n");
#endif
    }

    //time_end = 1;
}

void jsm1302z_init(void)
{
    jsm1302z_state = JSM1302Z_State_0x00;
    rcu_periph_clock_enable(RCU_GPIOB);
    gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,  GPIO_PIN_11);
    I2C_SCL_L;
    gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,  GPIO_PIN_12);
    gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,  GPIO_PIN_13);
    //RST_OFF;
    RST_ON;
    //RST_ON;
    //RST_ON;
    //gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4);
    //I2C_SDA_H;
    //I2C_SCL_H;
    jsm1302z_get_time_start();
}


void set_delay_lock(uint32_t lock_time)
{
    jsm1302z_lock_time = lock_time;
    jsm1302z_get_time_start();
    jsm1302z_set_ram_time_start();
}

